/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package client.model;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryonet.Client;
import com.esotericsoftware.kryonet.Connection;
import com.esotericsoftware.kryonet.Listener;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import static java.lang.Thread.sleep;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import static client.controller.ClientController.HOST_ADRESS;
import static client.controller.ClientController.TIME_OUT;
import network.szyfrowanie.Klucze;
import network.szyfrowanie.SzyfrowanieRSA;
import sun.security.rsa.RSAPublicKeyImpl;

/**
 *
 * @author mikolaj
 */
public class UstalanieKlucza extends SzyfrowanieRSA {
    private Client client;
    private boolean kon;//Czy ustalono klucz
    private byte[] Klucz;
    public PublicKey pubs;//Klucz publiczny serwera Do zmianyna private!!
    private final PublicKey pub;
    private PrivateKey priv;
    int port;
    
    
    public UstalanieKlucza(final int port) throws NoSuchAlgorithmException, IOException, InvalidKeyException{
        final KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
        final KeyPair keyPair = generator.generateKeyPair();
        pub = keyPair.getPublic(); //klucz publiczny
        priv = keyPair.getPrivate(); //klucz prywatny
        kon=false;
        this.port=port;
        
        UstawKlucz();//pubs
        
        this.client = new Client();
        client.start();
        
        
        Kryo kryo = client.getKryo();//Rejestrujemy klasy do serwera
	kryo.register(Klucze.class);
        kryo.register(byte[].class);
        kryo.register(String.class);
        
        
    }
    
    
    
    public void ustaw(){
        client.addListener(new Listener() {
            @Override
                public void connected(Connection con){
                    System.out.println("Połączono");                
                    client.sendTCP(pub.getEncoded());
                }
                
                
            @Override
            public void disconnected(Connection connection) {
                  System.out.println("Rozłączono");
            }

            @Override
            public void received(Connection connection, Object object) {
                if (object instanceof Klucze) {
                    try {
                        Klucze request =(Klucze) object;
                        boolean wer= true;
                        wer=weryfikuj(request.getPublic(),request.getPodpis());
                        if(wer){
                            try {
                                KeyGenerator kGen = KeyGenerator.getInstance("AES"); //Tworzenie klucza poczatek
                                kGen.init(128);
                                SecretKey sKey = kGen.generateKey();
                                byte[] rawKey = sKey.getEncoded();// Tworzenie klucza koniec
                                byte[] zasz=szyfruj(rawKey,request.getPublic());
                                byte[] rkey=odszyfruj(request.getKlucz(),priv);
                                client.sendTCP(new Klucze(request.getSesja(),zasz));
                                Klucz=new byte[rawKey.length];
                                for(int i=0;i<Klucz.length;i++){
                                    Klucz[i]=(byte) (rawKey[i]^rkey[i]);
                                    //System.out.println(Klucz[i]);
                                }
                                koniec();
                                client.close();
                            } catch (                NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException ex) {
                                Logger.getLogger(UstalanieKlucza.class.getName()).log(Level.SEVERE, null, ex);
                            }
                        }
                        else{
                            System.out.println("Błąd weryfikacji kluczy");
                        }
                    } catch (NoSuchAlgorithmException ex) {
                        Logger.getLogger(UstalanieKlucza.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (NoSuchPaddingException ex) {
                        Logger.getLogger(UstalanieKlucza.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (InvalidKeyException ex) {
                        Logger.getLogger(UstalanieKlucza.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (IllegalBlockSizeException ex) {
                        Logger.getLogger(UstalanieKlucza.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (BadPaddingException ex) {
                        Logger.getLogger(UstalanieKlucza.class.getName()).log(Level.SEVERE, null, ex);
                    }
                   
                }
                
            }
        });
        
        
        new Thread("Connect") {
            @Override
            public void run () {
                try {
                 //   client.connect(TIME_OUT, "127.0.0.1", port);
                    client.connect(TIME_OUT, HOST_ADRESS, port);
                } catch (IOException ex) {
                    Logger.getLogger(UstalanieKlucza.class.getName()).log(Level.SEVERE, null, ex);
                }
             }
        }.start();
    }
        private void koniec(){
            kon=true;
        }
    
        public byte[] getKlucz() throws InterruptedException{
            while(!kon){sleep(1000);}
            return Klucz;
        }
        
        private void UstawKlucz() throws InvalidKeyException{
            byte[] sb=new byte[162];
            File file = new File("public");
            FileInputStream fis = null;

            try {
                fis = new FileInputStream(file);

                 int content;
                 int i=0;
                int read = fis.read(sb);

            } catch (IOException e) {
    } finally {
        try {
            if (fis != null)
                fis.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
            pubs=new RSAPublicKeyImpl(sb);
        //    RSAPublicKeyImpl a=(RSAPublicKeyImpl)pubs;
        //    System.out.println(a.getModulus());
}
        //Do zmiany na private
        private boolean weryfikuj(PublicKey k,byte[] podpis) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{
            if(pubs==null)
                return true;
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            md.update(k.getEncoded());
            byte[] hashed = md.digest();
           /* for(int i=0;i<podpis.length;i++){
                System.out.println("podpis["+i+"] = "+podpis[i]);
          //  podpis[i]=0;
            }*/
            byte[] pod=szyfruj(podpis,pubs,1);
            boolean zw=true;
            if(hashed.length!=pod.length)
                return false;
            for(int i=0;i<hashed.length;i++)
                if(hashed[i]!=pod[i]){
                    zw=false;
                    break;
                }
            return zw;
        }
        
        public static void main(String [] args) throws NoSuchAlgorithmException, IOException, InterruptedException, InvalidKeyException{
            UstalanieKlucza uk=new UstalanieKlucza(54555);
            uk.ustaw();
            byte[] klucz=uk.getKlucz();
            for(int i=0;i<klucz.length;i++){
                System.out.println(i+": "+klucz[i]);
            }
          //  uk.wyslij();
            
        }
    
}
